package cc.risingsun.wing.core;

import static cc.risingsun.wing.core.generator.WingGeneratorUtil.getTypeGenerator;

import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map.Entry;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.util.TraceClassVisitor;

import cc.risingsun.wing.core.generator.WingTypeGenerator;
import cc.risingsun.wing.ds.DataStruct;
import cc.risingsun.wing.util.MultiValueMap;

/**
 * 
 * @author iron.yin@gmail.com
 * @sina 2012-9-10
 */

class WingFactory extends ClassLoader {

	private static final MultiValueMap<Class<? extends Annotation>, WingClass> map = DataStruct.multiValueMap();

	private final WingContext context;

	public WingFactory(WingContext context) {
		this.context = context;
	}

	static void addClass(WingClass wingClass) {
		for (Entry<Class<? extends Annotation>, WingAnnotation> e : wingClass.getAnnotations().entrySet()) {
			map.add(e.getKey(), wingClass);
		}
	}

	public void process() throws Exception {
		TraceClassVisitor tcv = new TraceClassVisitor(new PrintWriter(System.out));
		WingTypeGenerator generator;
		for (Entry<Class<? extends Annotation>, List<WingClass>> e : map.entrySet()) {
			generator = getTypeGenerator(e.getKey());
			for (WingClass wc : e.getValue()) {
				byte[] bytes = generating(wc, generator);
				ClassReader cr = new ClassReader(bytes);
				cr.accept(tcv, 0);
				Class<?> clazz = defineClass(wc.getClassName(), bytes, 0, bytes.length);
				context.putBean(wc.getClazz(), clazz.newInstance());
			}
		}
	}

	private byte[] generating(WingClass wc, WingTypeGenerator gen) {
		gen.constructor(wc);
		WingMethod method;
		for (Entry<String, WingMethod> e : wc.getMethods().entrySet()) {
			method = e.getValue();
			gen.generateMethod(method);
		}
		return gen.toByte();
	}
}
